package com.brayan.webapp.service.realestate;

import java.util.Date;

import javax.ejb.Stateless;
import javax.inject.Inject;

import org.joda.time.Days;
import org.joda.time.LocalDate;

@Stateless
public class PriceModelBean {

	private static final int MAX_GUESTS = 6;
	private static final int MIN_GUESTS = 2;
	private static final int MAX_LIGHT_BEDS = 2;
	private static final double PRICE_PER_NIGHT_AND_PERSON = 65;
	/** Always to calculate from the new discout */
	private static final double DISCOUNT_FACTOR_PERSON = 0.11;
	/** Always to calculate from the new discount */
	private static final double DISCOUNT_FACTOR_NIGHTS = 0.03;

	private static final double MIN_CLEANING_FEE = 55;
	private static final double CLEANING_FEE_INCREASE_FACTOR = 0.05;

	private static final String CURRENCY = "EUR";
	private static final double VAT = 0.25;

	@Inject
	SeasonFactorBean seasonFactorService;

	/**
	 * This calculates the reservation costs only. No VAT, no cleaning and no
	 * other fees are included.
	 * 
	 * @return
	 */
	public double calculateReservationCosts(int numberOfGuests,
			LocalDate startDate, LocalDate endDate) {

		int nights = getNights(getDurationInDays(startDate, endDate));

		double total = numberOfGuests * nights * PRICE_PER_NIGHT_AND_PERSON;
		// Add the season factor discount.
		double seasonFactorAmount = seasonFactorService
				.calculateSeasonFactorAmount(startDate, endDate, total);
		total += seasonFactorAmount;

		// Apply the guest discount.
		for (int i = 1; i < numberOfGuests; i++) {
			total = total * (1 - (DISCOUNT_FACTOR_PERSON));
		}
		// Apply discount for number of nights.
		for (int i = 1; i < nights; i++) {
			total = total * (1 - (DISCOUNT_FACTOR_NIGHTS));
		}
		return rounding(total);
	}
	
	public double calculateAverageSeasonFactor(LocalDate startDate, LocalDate endDate){
		return seasonFactorService.calculateAverageFactor(startDate, endDate);
	}

	public int getDurationInDays(LocalDate startDate, LocalDate endDate) {
		int numOfDays = Days.daysBetween(startDate, endDate).getDays()+1;
		return numOfDays;
	}
	
	public int getDurationInDays(Date startDate, Date endDate){
		int numOfDays = Days.daysBetween(new LocalDate(startDate), new LocalDate(endDate)).getDays()+1;
		return numOfDays;
	}

	private int getNights(int days) {
		return days -1;
	}

	public String getCurrency() {
		return CURRENCY;
	}

	public double calculateCleaningFee(int days, int numberOfGuests) {

		double cleaningFee = MIN_CLEANING_FEE;
		for (int i = 1; i < days; i++) {
			cleaningFee = cleaningFee * (1 + CLEANING_FEE_INCREASE_FACTOR);
		}

		int numOfGuests = getNumberOfGuests(numberOfGuests);
		for (int i = 1; i < numOfGuests; i++) {
			cleaningFee = cleaningFee * (1 + CLEANING_FEE_INCREASE_FACTOR);
		}

		return rounding(cleaningFee);
	}

	public double getVAT() {
		return VAT;
	}

	public double getVatAmount(double reservationCosts, double cleaningFee) {
		double vatAmount = (reservationCosts + cleaningFee) * (VAT);
		return rounding(vatAmount);
	}

	/**
	 * calculate total costs including the VAT
	 * @param reservationCosts
	 * @param cleaningFee
	 * @return
	 */
	public double calculateTotalCosts(double reservationCosts,
			double cleaningFee) {
		double total = (reservationCosts + cleaningFee) * (1 + VAT);
		return rounding(total);
	}

	private double rounding(double amount) {
		double roundedAmount = amount * 10;
		roundedAmount = Math.round(roundedAmount);
		return roundedAmount / 10;
	}

	public int getNumberOfGuests(int numberOfGuests) {
		int numOfGuests;

		if (numberOfGuests < MIN_GUESTS)
			numOfGuests = MIN_GUESTS;
		else if (numberOfGuests > MAX_GUESTS)
			numOfGuests = MAX_GUESTS;
		else
			numOfGuests = numberOfGuests;
		return numOfGuests;
	}
}
